﻿using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;

namespace HTPCRemoteServer
{
    internal class NativeMethods
    {
        public const int WM_SETTEXT = 0x000C;
        public const int WM_CHAR = 0x0102;

        public static UInt32 SendInputEx(NativeMethods.INPUT input)
        {
            UInt32 rv = 0;
            if ((IntPtr.Size == 8))
            {
                NativeMethods.INPUT64 input64 = new NativeMethods.INPUT64();
                input64.type = input.type;
                if (input.type == 1) // Keyboard
                {
                    input64.ki.wVk = input.ki.wVk;
                    input64.ki.wScan = input.ki.wScan;
                    input64.ki.dwFlags = input.ki.dwFlags;
                    input64.ki.time = input.ki.time;
                    input64.ki.dwExtraInfo = input.ki.dwExtraInfo;
                }
                else // Mouse
                {
                    input64.mi.dx = input.mi.dx;
                    input64.mi.dy = input.mi.dy;
                    input64.mi.dwFlags = input.mi.dwFlags;
                    input64.mi.mouseData = input.mi.mouseData;
                    input64.mi.time = input.mi.time;
                    input64.mi.dwExtraInfo = input.mi.dwExtraInfo;
                }
                NativeMethods.INPUT64[] inputs = { input64 };
                rv = NativeMethods.SendInput64(1, inputs, Marshal.SizeOf(input64));
            }
            else
            {
                NativeMethods.INPUT[] inputs = { input };
                rv = NativeMethods.SendInput(1, inputs, Marshal.SizeOf(input));
            }
            return rv;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        internal static extern short VkKeyScan(char key);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        internal static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        internal static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool PostMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);

        internal enum InputType
        {
            INPUT_MOUSE = 0,
            INPUT_KEYBOARD = 1,
            INPUT_HARDWARE = 2,
        }

        [Flags()]
        internal enum MOUSEEVENTF
        {
            MOVE = 0x0001,
            LEFTDOWN = 0x0002,
            LEFTUP = 0x0004,
            RIGHTDOWN = 0x0008,
            RIGHTUP = 0x0010,
            MIDDLEDOWN = 0x0020,
            MIDDLEUP = 0x0040,
            XDOWN = 0x0080,
            XUP = 0x0100,
            WHEEL = 0x0800,
            VIRTUALDESK = 0x4000,
            ABSOLUTE = 0x8000,
        }

        [Flags()]
        internal enum KEYEVENTF
        {
            KEYDOWN = 0x0000,
            EXTENDEDKEY = 0x0001,
            KEYUP = 0x0002,
            UNICODE = 0x0004,
            SCANCODE = 0x0008,
        }

        //http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx
        [StructLayout(LayoutKind.Sequential)]
        internal struct MOUSEINPUT
        {
            internal int dx;
            internal int dy;
            internal int mouseData;
            internal int dwFlags;
            internal int time;
            internal IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct KEYBDINPUT
        {
            internal short wVk;
            internal short wScan;
            internal int dwFlags;
            internal int time;
            internal IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct HARDWAREINPUT
        {
            internal int uMsg;
            internal short wParamL;
            internal short wParamH;
        }

        [SuppressMessage("Microsoft.Portability", "CA1900:ValueTypeFieldsShouldBePortable")]
        [StructLayout(LayoutKind.Explicit)]
        internal struct INPUT
        {
            [FieldOffset(0)]
            internal int type;

            [FieldOffset(4)]
            internal MOUSEINPUT mi;

            [FieldOffset(4)]
            internal KEYBDINPUT ki;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct INPUT64
        {
            [FieldOffset(0)]
            internal int type;

            [FieldOffset(8)]
            internal MOUSEINPUT mi;

            [FieldOffset(8)]
            internal KEYBDINPUT ki;
        }

        [DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
        internal static extern UInt32 SendInput(UInt32 nInputs, INPUT[] pInputs, int cbSize);

        [DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
        internal static extern UInt32 SendInput64(UInt32 nInputs, INPUT64[] pInputs, int cbSize);

        [DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)]
        internal static extern IntPtr GetMessageExtraInfo();

        [DllImport("user32.dll", EntryPoint = "LockWorkStation", SetLastError = true)]
        internal static extern UInt32 LockWorkStation();

        [DllImport("user32.dll")]
        internal static extern UInt32 MapVirtualKey(UInt32 uCode, UInt32 uMapType);
    }
}
